/*
 * Galaxium Messenger
 * Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Runtime.InteropServices;

using Anculus.Core;

using Galaxium.Core;
using Galaxium.Client;

namespace Galaxium.GStreamer
{
	public class GStreamerSoundPlayer : ISoundPlayer
	{
		public event EventHandler EndOfStream;
		public event EventHandler Error;
		
		IntPtr _native;
		HandleRef _handle;
		
		GCHandle _eosHandle;
		GCHandle _errorHandle;
		
		bool _disposed;
		
		public GStreamerSoundPlayer (IntPtr native)
		{
			_native = native;
			
			//Log.Debug ("Created, native={0}", native);
			
			ThrowUtility.ThrowIfTrue ("Native pointer is null", _native == IntPtr.Zero);
			
			_handle = new HandleRef (this, _native);
			
			GStreamerEosCallback eosCallback = new GStreamerEosCallback (CallbackEOS);
			GStreamerErrorCallback errorCallback = new GStreamerErrorCallback (CallbackError);
			
			_eosHandle = GCHandle.Alloc (eosCallback, GCHandleType.Pinned);
			_errorHandle = GCHandle.Alloc (errorCallback, GCHandleType.Pinned);
			
			GStreamerInterop.libgalaxium_gstreamer_set_eos_callback (_handle, eosCallback);
			GStreamerInterop.libgalaxium_gstreamer_set_error_callback (_handle, errorCallback);
		}
		
		~GStreamerSoundPlayer ()
		{
			Dispose (true);
		}
		
		public void Dispose ()
		{
			Dispose (false);
			
			GC.SuppressFinalize (this);
		}
		
		void Dispose (bool destroyed)
		{
			//Log.Debug ("Dispose");
			
			if (!_disposed)
			{
				_disposed = true;
				
				GStreamerInterop.libgalaxium_gstreamer_close (_handle);
				
				_eosHandle.Free ();
				_errorHandle.Free ();
			}
		}
		
		public void Play ()
		{
			if (_disposed)
				return;
			
			GStreamerInterop.libgalaxium_gstreamer_play (_handle);
		}
		
		public void Stop ()
		{
			if (_disposed)
				return;
			
			GStreamerInterop.libgalaxium_gstreamer_stop (_handle);
		}
		
		void CallbackEOS (IntPtr native)
		{
			if (_disposed)
				return;
			
			// Be very careful we don't throw any unhandled exceptions in these callback methods
			
			try
			{
				//Log.Debug ("End Of Stream");
				
				Stop ();
				
				if (EndOfStream != null)
					EndOfStream (this, EventArgs.Empty);
			}
			catch (Exception ex)
			{
				Log.Error (ex, "Error in end of stream handler");
			}
		}
		
		void CallbackError (IntPtr native, uint domain, int code, IntPtr error, IntPtr debug)
		{
			if (_disposed)
				return;
			
			try
			{
				Stop ();
				
				string errorMsg = error == IntPtr.Zero ? "Unknown Error" : GLib.Marshaller.Utf8PtrToString (error);
				
				Log.Error (errorMsg);
				
				if (Error != null)
					Error (this, EventArgs.Empty);
			}
			catch (Exception ex)
			{
				Log.Error (ex, "Error in error handler...");
			}
		}
	}
}
